// Fill out your copyright notice in the Description page of Project Settings.


#include "AnimPlayer/MotionSubtitlesAnimPlayer.h"
#include "AnimPlayer/Actions/ActionFactory.h"

void FMotionSubtitlesAnimPlayer::Init(const FAnimAttributes& AnimAttributes)
{
	// 清理旧数据
	Reset();

	// 创建行为参数
	FActionAttributes ActionAttributes;
	CreateActionAttributes(AnimAttributes, ActionAttributes);

	// 根据实际时间，调整行为时长
	ScaleActions(ActionAttributes);

	// 创建行为
	CreateActions(ActionAttributes);

	// 设置初始状态
	PlayerState = EAnimPlayerState::Initialized;
}

void FMotionSubtitlesAnimPlayer::Tick(float DeltaTime)
{
	// 未初始化，直接退出
	if (PlayerState == EAnimPlayerState::None)
	{
		return;
	}

	// 所有行为执行完成，直接退出
	if (PlayerState == EAnimPlayerState::Done)
	{
		return;
	}

	// 第一次Tick，自动进入Enter状态
	if (PlayerState == EAnimPlayerState::Initialized)
	{
		SwitchState(EAnimPlayerState::Enter);
	}

	// 更新计时器
	Timer += DeltaTime;

	//const FString State = UEnum::GetValueAsString(PlayerState);
	//UE_LOG(LogTemp, Error, TEXT("======= State:%s Time:%f"), *State, Timer);

	// 行为播放驱动
	float Counter = 0;
	for (const auto Item : CurrentActions)
	{
		if (Item->BeginTime <= Timer && !Item->IsTriggered)
		{
			Item->OnBegin();
		}
		if (Item->IsTriggered && !Item->IsCompleted)
		{
			Item->OnTick(DeltaTime);
		}
		if (Item->EndTime <= Timer && !Item->IsCompleted)
		{
			Item->OnEnd();
		}

		if (Item->IsCompleted)
		{
			Counter++;
		}
	}

	// 切换状态
	if (Counter == CurrentActions.Num())
	{
		if (PlayerState == EAnimPlayerState::Enter && EnterDuration <= Timer)
		{
			SwitchState(EAnimPlayerState::Stay);
			return;
		}

		if (PlayerState == EAnimPlayerState::Stay && StayDuration <= Timer)
		{
			SwitchState(EAnimPlayerState::Exit);
			return;
		}

		if (PlayerState == EAnimPlayerState::Exit && ExitDuration <= Timer)
		{
			SwitchState(EAnimPlayerState::Done);
			return;
		}
	}
}

void FMotionSubtitlesAnimPlayer::Exit()
{
	Reset();
}

void FMotionSubtitlesAnimPlayer::Reset()
{
	EnterActions.Empty();
	StayActions.Empty();
	ExitActions.Empty();
	CurrentActions.Empty();
	PlayerState = EAnimPlayerState::None;
	Timer = 0;
}

void FMotionSubtitlesAnimPlayer::CreateActionAttributes(const FAnimAttributes& AnimAttributes,
                                                        FActionAttributes& ActionAttributes)
{
	// 生成Enter状态动画行为
	CreateActionAttributes(AnimAttributes.EnterAnimations, AnimAttributes.Layers, ActionAttributes.EnterAnimations);

	// 生成Stay状态动画行为
	CreateActionAttributes(AnimAttributes.StayAnimations, AnimAttributes.Layers, ActionAttributes.StayAnimations);

	// 生成Exit状态动画行为
	CreateActionAttributes(AnimAttributes.ExitAnimations, AnimAttributes.Layers, ActionAttributes.ExitAnimations);

	ActionAttributes.Layers = AnimAttributes.Layers;
	ActionAttributes.Duration = AnimAttributes.Duration;
}

void FMotionSubtitlesAnimPlayer::CreateActionAttributes(const TArray<FMotionAnimInfo>& AnimInfos,
                                                        const TArray<TWeakObjectPtr<UMotionSubtitlesLayerBase>>&
                                                        Layers, TArray<FAnimActionInfo>& ActionInfos)
{
	for (int32 i = 0; i < AnimInfos.Num(); i++)
	{
		TWeakObjectPtr<UMotionSubtitlesLayerBase> Layer = nullptr;
		const int32 LayerIndex = static_cast<int32>(AnimInfos[i].TargetLayer);
		if (!Layers.IsValidIndex(LayerIndex))
		{
			continue;
		}
		Layer = Layers[LayerIndex];

		if (AnimInfos[i].DispatchMode == EDispatchMode::ContentElement)
		{
			const int32 Count = Layer->ElementCount();
			for (int32 j = 0; j < Count; j++)
			{
				FAnimActionInfo ActionInfo = FAnimActionInfo::From(AnimInfos[i]);
				ActionInfo.Layer = Layer;
				ActionInfo.ElementId = j;
				ActionInfo.StartOffset *= j;
				ActionInfos.Add(ActionInfo);
			}
		}
		else
		{
			FAnimActionInfo ActionInfo = FAnimActionInfo::From(AnimInfos[i]);
			ActionInfo.Layer = Layer;
			ActionInfo.ElementId = -1;
			ActionInfos.Add(ActionInfo);
		}
	}
}

void FMotionSubtitlesAnimPlayer::SwitchState(const EAnimPlayerState& NewState)
{
	// 相同状态，不切换
	if (PlayerState == NewState)
	{
		return;
	}
	PlayerState = NewState;
	Timer = 0;

	// 当前行为序列清理
	for (const auto Element : CurrentActions)
	{
		Element->OnExit();
	}

	// 切换当前执行的行为序列
	switch (NewState)
	{
	case EAnimPlayerState::Enter:
		CurrentActions = EnterActions;
		break;
	case EAnimPlayerState::Stay:
		CurrentActions = StayActions;
		break;
	case EAnimPlayerState::Exit:
		CurrentActions = ExitActions;
		break;
	default:
		CurrentActions = TArray<TSharedPtr<FActionBase>>();
		break;
	}

	// 当前行为序列初始化
	for (const auto Element : CurrentActions)
	{
		Element->OnInit();
	}
}

void FMotionSubtitlesAnimPlayer::CreateActions(const FActionAttributes& ActionAttributes)
{
	CreateActions(ActionAttributes.EnterAnimations, EnterActions);
	CreateActions(ActionAttributes.StayAnimations, StayActions);
	CreateActions(ActionAttributes.ExitAnimations, ExitActions);
}


void FMotionSubtitlesAnimPlayer::CreateActions(const TArray<FAnimActionInfo>& ActionInfos,
                                               TArray<TSharedPtr<FActionBase>>& Actions)
{
	for (auto Info : ActionInfos)
	{
		TSharedPtr<FActionBase> ActionBase = nullptr;
		if (FActionFactory::Create(Info, ActionBase))
		{
			Actions.Add(ActionBase);
		}
		else
		{
			const FString EnumStr = UEnum::GetValueAsString(Info.Type);
			UE_LOG(LogTemp, Error, TEXT("行为创建失败,未知的动画类型:%s"), *EnumStr);
		}
	}
}

float FMotionSubtitlesAnimPlayer::CalcStateDuration(const TArray<FAnimActionInfo>& ActionInfos)
{
	float Duration = 0;
	for (const auto Element : ActionInfos)
	{
		const float StartTime = ((Element.AnimTarget == EAnimTarget::ContentElement) ? Element.StartOffset : 0);
		const float EndTime = StartTime + Element.Duration;

		if (EndTime >= Duration)
		{
			Duration = EndTime;
		}
	}
	return Duration;
}

void FMotionSubtitlesAnimPlayer::ScaleActions(FActionAttributes& ActionAttributes)
{
	const float OriginEnterDuration = CalcStateDuration(ActionAttributes.EnterAnimations);
	const float OriginStayDuration = CalcStateDuration(ActionAttributes.StayAnimations);
	const float OriginExitDuration = CalcStateDuration(ActionAttributes.ExitAnimations);
	const float OriginTotalDuration = OriginEnterDuration + OriginStayDuration + OriginExitDuration;

	// 缩放Enter动画
	EnterDuration = 0;
	ScaleStateDuration(OriginEnterDuration, OriginTotalDuration, EnterDuration, ActionAttributes.Duration,
	                   ActionAttributes.EnterAnimations);

	// 缩放Exit动画
	ExitDuration = 0;
	ScaleStateDuration(OriginExitDuration, OriginTotalDuration, ExitDuration, ActionAttributes.Duration,
	                   ActionAttributes.ExitAnimations);

	// 缩放Stay动画
	StayDuration = ActionAttributes.Duration - EnterDuration - ExitDuration;
	if (!FMath::IsNearlyZero(OriginStayDuration))
	{
		const float ScaleRate = FMathf::Max(0, StayDuration / OriginStayDuration);
		ScaleStateDuration(ScaleRate, ActionAttributes.StayAnimations,true);
	}
}


void FMotionSubtitlesAnimPlayer::ScaleStateDuration(const float OriginStateDuration, const float OriginTotalDuration,
                                                    float& RealStateDuration, const float RealDuration,
                                                    TArray<FAnimActionInfo>& ActionInfos)
{
	float Rate = 0;
	if (!FMath::IsNearlyZero(OriginTotalDuration))
	{
		Rate = OriginStateDuration / OriginTotalDuration;
	}

	RealStateDuration = FMath::Min(Rate * RealDuration, OriginStateDuration);
	float ScaleRate = 0;
	if (!FMath::IsNearlyZero(OriginStateDuration))
	{
		ScaleRate = RealStateDuration / OriginStateDuration;
	}

	ScaleStateDuration(ScaleRate, ActionInfos);
}

void FMotionSubtitlesAnimPlayer::ScaleStateDuration(const float ScaleRate, TArray<FAnimActionInfo>& ActionInfos,bool AlwaysScaleStartOffset)
{
	for (auto& Element : ActionInfos)
	{
		if(AlwaysScaleStartOffset==false)
		{
			// 只有缩放时，才调整开始偏移
			if (ScaleRate >= 0 && ScaleRate <= 1)
			{
				Element.StartOffset *= ScaleRate;
			}	
		}
		else
		{
			Element.StartOffset *= ScaleRate;
		}
		Element.Duration *= ScaleRate;
	}
}
